package com.jboost.modules.system.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.jboost.common.api.vo.Result;
import com.jboost.common.constant.CacheConstant;
import com.jboost.common.constant.CommonConstant;
import com.jboost.common.exception.JBoostException;
import com.jboost.common.file.constant.JboostFileConstant;
import com.jboost.common.system.api.ISysBaseAPI;
import com.jboost.common.system.vo.DictModel;
import com.jboost.common.util.*;
import com.jboost.common.util.qiniu.QiniuUploadTokenVo;
import com.jboost.common.util.qiniu.QiniuUtil;
import com.jboost.common.util.oss.OssBootUtil;
import com.jboost.modules.file.entity.JboostFile;
import com.jboost.modules.file.service.IJboostFileService;
import com.jboost.modules.system.service.ISysDictService;
import com.jboost.modules.system.vo.CscFileChunkVo;
import com.jboost.modules.system.vo.CscFileVo;
import com.jboost.modules.system.vo.ObsInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.FileCopyUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.*;
import java.net.URLDecoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 前端控制器
 * </p>
 *
 * @Author scott
 * @since 2018-12-20
 */
@Slf4j
@Api(tags="公共类 API")
@RestController
@RequestMapping("/sys/common")
public class CommonController {

    @Autowired
    private ISysBaseAPI sysBaseAPI;

    @Value(value = "${jeecg.path.upload}")
    private String uploadpath;

    /**
     * 本地：local minio：minio 阿里：alioss
     */
    @Value(value = "${jeecg.uploadType}")
    private String uploadType;

    /**
     * 本地保存时，访问的 host
     */
    @Value(value = "${server.host}")
    private String webHost;
    @Autowired
    ISysDictService iSysDictService;
    /**
     * 本地保存，访问的 port
     */
    @Value(value = "${server.visit-port}")
    private String port;
    /**
     * 本地保存，访问的 context
     */
    @Value(value = "${server.servlet.context-path}")
    private String context;

    @Autowired
    private IJboostFileService fileService;

    @Autowired
    private RedisUtil redisUtil;

    @Value("${jeecg.oss.endpoint}")
    private String ossEndpoint;

    @Value("${jeecg.oss.accessKey}")
    private String ossAccessKey;

    @Value("${jeecg.oss.secretKey}")
    private String ossSecretKey;

    @Value("${jeecg.oss.bucketName}")
    private String ossBucketName;

    @Value("${jeecg.oss.sts.endpoint}")
    private String stsEndpoint;

    @Value("${jeecg.oss.sts.accessKey}")
    private String stsAccessKey;

    @Value("${jeecg.oss.sts.secretKey}")
    private String stsSecretKey;

    @Value("${jeecg.oss.sts.roleArn}")
    private String stsRoleArn;

    @Autowired
    private ISysDictService sysDictService;
    /**
     * @return
     * @Author 政辉
     */
    @GetMapping("/403")
    public Result<?> noauth() {
        return Result.error("没有权限，请联系管理员授权");
    }

    /**
     * 文件分片上传
     * TODO 一，文件的identifier唯一标识，使用UUID。
     * 二，与前端约定合并文件的请求。返回文件预览地址。
     *
     * @param request
     * @param multipartFile
     * @param chunk
     * @return
     */
//    @PostMapping("/chunkUploadLocal")
    @PostMapping("/chunkUpload")
    public Result<?> uploadFiles(HttpServletRequest request, @RequestParam("file") MultipartFile multipartFile, CscFileChunkVo chunk) {

        if (multipartFile.isEmpty()) {
            return Result.error("文件不能为空！");
        } else {
            //uuid -> 生成的文件名称中的UUID, originFileName -> 文件原始名, uploadFileName -> 保存在本地的文件名称
            String uuid = null, originFileName = null, uploadFileName = null;

            synchronized (CommonController.class) {
                //文件存储目录
                File chunkDir = new File(uploadpath + File.separator);
                if (!chunkDir.exists()) {
                    chunkDir.mkdirs();
                }
                //获取缓存中的文件信息
                Object chunkCache = redisUtil.get(CacheConstant.FILE_CHUNK_IDENTIFIER + chunk.getIdentifier());
                if (chunkCache == null) {
                    // 文件原名称
                    originFileName = chunk.getFilename();
                    // 上传文件重命名
                    uuid = UUID.randomUUID().toString(true).substring(0, 16);
                    uploadFileName = uuid + "-" + originFileName;
                    chunk.setOriginFileName(originFileName);
                    chunk.setUploadFileName(uploadFileName);
                    chunk.setFileUuid(uuid);
                    //如果缓存未命中，说明这是第一个文件分片, 将文件信息存进缓存，5分钟
                    redisUtil.set(CacheConstant.FILE_CHUNK_IDENTIFIER + chunk.getIdentifier(), chunk, 300);
                } else {
                    //命中则拿到文件信息
                    CscFileChunkVo originalChunk = (CscFileChunkVo) chunkCache;
                    uuid = originalChunk.getFileUuid();
                    uploadFileName = originalChunk.getUploadFileName();
                    originFileName = originalChunk.getOriginFileName();
                }
            }
            //存储在本地的文件对象
            File file = new File(uploadpath + File.separator + uploadFileName);
            //进行写文件操作
            try (
                    //将块文件写入文件中
                    InputStream fos = multipartFile.getInputStream();
                    RandomAccessFile raf = new RandomAccessFile(file, "rw")
            ) {
                int len = -1;
                byte[] buffer = new byte[1024];
                raf.seek((long) (chunk.getChunkNumber() - 1) * 1024 * 1024);
                while ((len = fos.read(buffer)) != -1) {
                    raf.write(buffer, 0, len);
                }
                long incr;
                //有可能发生分片请求有几个请求丢失，所以不能直接incr，incr无法设置超时时间
                synchronized (CommonController.class) {
                    Object chunkNums = redisUtil.get(CacheConstant.FILE_CHUNK_IDENTIFIER + chunk.getIdentifier() + ":" + "chunkCount");
                    if (chunkNums == null) {
                        incr = 1;
                        redisUtil.set(CacheConstant.FILE_CHUNK_IDENTIFIER + chunk.getIdentifier() + ":" + "chunkCount", incr, 300);
                    } else {
                        incr = redisUtil.incr(CacheConstant.FILE_CHUNK_IDENTIFIER + chunk.getIdentifier() + ":" + "chunkCount", 1);
                    }
                }
                if (incr == chunk.getTotalChunks()) {
                    JSONObject jsonObject = saveFileToDataBase(chunk, uploadFileName);
                    redisUtil.del(CacheConstant.FILE_CHUNK_IDENTIFIER + chunk.getIdentifier() + ":" + "chunkCount");
                    redisUtil.del(CacheConstant.FILE_CHUNK_IDENTIFIER + chunk.getIdentifier());
                    return Result.OK("上传成功", jsonObject);
                }
            } catch (IOException e) {
                e.printStackTrace();
                file.delete();
                redisUtil.del(CacheConstant.FILE_CHUNK_IDENTIFIER + chunk.getIdentifier() + ":" + "chunkCount");
                redisUtil.del(CacheConstant.FILE_CHUNK_IDENTIFIER + chunk.getIdentifier());
                return Result.error("写入文件错误，请重新上传！");
            }
            return Result.OK(chunk.getIdentifier());
        }
    }

    /**
     * 保存合并好的文件到数据库
     */
    public JSONObject saveFileToDataBase(CscFileChunkVo chunk, String uploadFileName) {
        //总大小
        Long totalSize = chunk.getTotalSize();
        //文件真实名字
        String filename = chunk.getFilename();
        //文件后缀
        String fileExt = filename.substring(filename.lastIndexOf(".") + 1);

        JboostFile cscFile = new JboostFile();
        cscFile.setFileSize((double) (totalSize / 1024));
        cscFile.setAliasName(filename);
        cscFile.setFileStore("{\"type\":\"" + uploadType + "\",\"path\":\"" + uploadFileName + "\"}");
        cscFile.setFileExt(fileExt);
        // 生成文件编码
        StringBuilder sb = new StringBuilder();
        //固定开头
        sb.append(JboostFileConstant.ATTACH_CODE_START);
        //加文件格式
        sb.append(fileExt.toUpperCase()).append("-");
        int count = fileService.count();
        //加6位编码
        sb.append(SnUtils.getSn(count, 6));
        cscFile.setFileCode(sb.toString());
        boolean save = fileService.save(cscFile);
        if (!save) {
            throw new JBoostException("上传失败!");
        }
        String fileReviewUrl = "http://" + webHost + (port == null ? "" : (":" + port)) + context + "/sys/common/static/" + uploadFileName;
        //先简单实现
        JSONObject jsonResult = (JSONObject) JSON.toJSON(cscFile);
        jsonResult.put("fileUrl", fileReviewUrl);
        return jsonResult;
    }


    /**
     * 文件上传统一方法
     *
     * @param request
     * @param response
     * @return
     */
    @PostMapping(value = "/uploadLocal")
    public Result<?> upload(HttpServletRequest request, HttpServletResponse response) {
        Result<Object> result = new Result<>();
        String savePath = "";
        String bizPath = request.getParameter("biz");
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;


        MultipartFile file = multipartRequest.getFile("file");// 获取上传文件对象
        String originalFileName = file.getOriginalFilename();//文件名
        String fileName = originalFileName;//文件名
//        String fileName = null;//文件名
        String fileExt = ""; //文件格式
        long fileSize = file.getSize();//文件大小，单位字节
        String fileReviewUrl = "";
        if (originalFileName.indexOf(".") > 0) {
            String[] strs = originalFileName.split("\\.");
            fileExt = strs[strs.length - 1];
//            fileName = strs[0];
        }
//        if (null == fileName){
//            fileName = originalFileName;
//        }
        if (oConvertUtils.isEmpty(bizPath)) {
            if (CommonConstant.UPLOAD_TYPE_OSS.equals(uploadType)) {
                //未指定目录，则用阿里云默认目录 upload
                bizPath = "upload";
                //result.setMessage("使用阿里云文件上传时，必须添加目录！");
                //result.setSuccess(false);
                //return result;
            } else {
                bizPath = "";
            }
        }
        if (CommonConstant.UPLOAD_TYPE_LOCAL.equals(uploadType)) {
            //update-begin-author:lvdandan date:20200928 for:修改JEditor编辑器本地上传
            savePath = this.uploadLocal(file, bizPath);
            fileReviewUrl = "http://" + webHost + (port == null ? "" : (":" + port)) + context + "/sys/common/static/" + savePath;
            //update-begin-author:lvdandan date:20200928 for:修改JEditor编辑器本地上传
            /**  富文本编辑器及markdown本地上传时，采用返回链接方式
             //针对jeditor编辑器如何使 lcaol模式，采用 base64格式存储
             String jeditor = request.getParameter("jeditor");
             if(oConvertUtils.isNotEmpty(jeditor)){
             result.setMessage(CommonConstant.UPLOAD_TYPE_LOCAL);
             result.setSuccess(true);
             return result;
             }else{
             savePath = this.uploadLocal(file,bizPath);
             }
             */
        } else {
            //update-begin-author:taoyan date:20200814 for:文件上传改造
            savePath = CommonUtils.upload(file, bizPath, uploadType);
            //update-end-author:taoyan date:20200814 for:文件上传改造
            fileReviewUrl = savePath;
        }
        if (oConvertUtils.isNotEmpty(savePath)) {
//          保存一条 file 记录
            JboostFile cscFile = new JboostFile();
            cscFile.setFileSize((double) (fileSize / 1024));
            cscFile.setAliasName(fileName);
            cscFile.setFileStore("{\"type\":\"" + uploadType + "\",\"path\":\"" + savePath + "\"}");
            cscFile.setFileExt(fileExt);
            // 生成文件编码
            StringBuffer sb = new StringBuffer();
//            固定开头
            sb.append(JboostFileConstant.ATTACH_CODE_START);
//            加文件格式
            sb.append(fileExt.toUpperCase()).append("-");
            int count = fileService.count();
//            加6位编码
            sb.append(SnUtils.getSn(count, 6));
            cscFile.setFileCode(sb.toString());
            fileService.save(cscFile);
            result.setMessage("上传成功！");
//            JSONObject jsonObject = new JSONObject();
//            jsonObject.put("result",host+savePath);
            //先简单实现
            JSONObject jsonResult = (JSONObject) JSON.toJSON(cscFile);
            jsonResult.put("fileUrl", fileReviewUrl);
            result.setResult(jsonResult);
            result.setSuccess(true);
        } else {
            result.setMessage("上传失败！");
            result.setSuccess(false);
        }
        return result;
    }

    /**
     * 本地文件上传
     *
     * @param mf      文件
     * @param bizPath 自定义路径
     * @return
     */
    private String uploadLocal(MultipartFile mf, String bizPath) {
        try {
            String ctxPath = uploadpath;
            String fileName = null;
            File file = new File(ctxPath + File.separator + bizPath + File.separator);
            if (!file.exists()) {
                file.mkdirs();// 创建文件根目录
            }
            String orgName = mf.getOriginalFilename();// 获取文件名
            orgName = CommonUtils.getFileName(orgName);
            if (orgName.indexOf(".") != -1) {
                fileName = orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.indexOf("."));
            } else {
                fileName = orgName + "_" + System.currentTimeMillis();
            }
            String savePath = file.getPath() + File.separator + fileName;
            File savefile = new File(savePath);
            FileCopyUtils.copy(mf.getBytes(), savefile);
            String dbpath = null;
            if (oConvertUtils.isNotEmpty(bizPath)) {
                dbpath = bizPath + File.separator + fileName;
            } else {
                dbpath = fileName;
            }
            if (dbpath.contains("\\")) {
                dbpath = dbpath.replace("\\", "/");
            }
            return dbpath;
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return "";
    }

    @PostMapping("/upload")
    public Result<JSONObject> uploadAliyun(@RequestParam("file") MultipartFile file,String category) {
        Result result = new Result();
        String url = OssBootUtil.upload(file, OssBootUtil.getFileDir(category), ossBucketName);
        //文件格式
        String fileExt = "";
        //文件大小，单位字节
        long fileSize = file.getSize();
        String originalFileName = file.getOriginalFilename();
        if (originalFileName.indexOf(".") > 0) {
            String[] strs = originalFileName.split("\\.");
            fileExt = strs[strs.length - 1];
        }
        //保存一条 file 记录
        JboostFile cscFile = new JboostFile();
        cscFile.setFileSize((double) (file.getSize() / 1024));
        cscFile.setAliasName(file.getOriginalFilename());
        String uploadTypeForAliyun = CommonConstant.UPLOAD_TYPE_OSS;
        cscFile.setFileStore("{\"type\":\"" + uploadTypeForAliyun + "\",\"path\":\"" + url + "\"}");
        cscFile.setFileExt(fileExt);
        // 生成文件编码
        StringBuffer sb = new StringBuffer();
        //固定开头
        sb.append(JboostFileConstant.ATTACH_CODE_START);
        //加文件格式
        sb.append(fileExt.toUpperCase()).append("-");
        int count = fileService.count();
        //加6位编码
        sb.append(SnUtils.getSn(count, 6));
        cscFile.setFileCode(sb.toString());
        fileService.save(cscFile);
        result.setMessage("上传成功！");
        //先简单实现
        JSONObject jsonResult = (JSONObject) JSON.toJSON(cscFile);
        String fileReviewUrl = OssBootUtil.getFullUrl(url, ossBucketName);
        jsonResult.put("fileUrl", fileReviewUrl);
        result.setResult(jsonResult);
        result.setSuccess(true);
        return result;
    }

    @GetMapping(value = "previewOss")
    public void previewAndDownload(HttpServletRequest request, HttpServletResponse response, @RequestParam(name = "type", defaultValue = "download") String type) {
        // ISO-8859-1 ==> UTF-8 进行编码转换
        String imgPath = extractPathFromPattern(request);
        if (oConvertUtils.isEmpty(imgPath) || imgPath == "null") {
            return;
        }
        // 其余处理略
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            imgPath = imgPath.replace("..", "");
            if (imgPath.endsWith(",")) {
                imgPath = imgPath.substring(0, imgPath.length() - 1);
            }
            String filePath = uploadpath + File.separator + imgPath;
            File file = new File(filePath);
            if (!file.exists()) {
                response.setStatus(404);
                throw new RuntimeException("文件不存在..");
            }
            if ("download".equals(type)) {
                response.setContentType("application/force-download");// 设置强制下载不打开
                response.addHeader("Content-Disposition", "attachment;fileName=" + new String(file.getName().getBytes("UTF-8"), "iso-8859-1"));
            }
            inputStream = new BufferedInputStream(new FileInputStream(filePath));
            outputStream = response.getOutputStream();
            byte[] buf = new byte[1024];
            int len;
            while ((len = inputStream.read(buf)) > 0) {
                outputStream.write(buf, 0, len);
            }
            response.flushBuffer();
        } catch (IOException e) {
            log.error("预览文件失败" + e.getMessage());
            response.setStatus(404);
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }

    }

    /**
     * 预览图片&下载文件
     * 请求地址：http://localhost:8080/common/static/{user/20190119/e1fe9925bc315c60addea1b98eb1cb1349547719_1547866868179.jpg}
     *
     * @param request
     * @param response
     */
    @GetMapping(value = "/static/**")
    public void view(HttpServletRequest request, HttpServletResponse response, @RequestParam(name = "type", defaultValue = "download") String type) {
        // ISO-8859-1 ==> UTF-8 进行编码转换
        String imgPath = extractPathFromPattern(request);
        if (oConvertUtils.isEmpty(imgPath) || imgPath == "null") {
            return;
        }
        // 其余处理略
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            imgPath = imgPath.replace("..", "");
            if (imgPath.endsWith(",")) {
                imgPath = imgPath.substring(0, imgPath.length() - 1);
            }
            String filePath = uploadpath + File.separator + imgPath;
            File file = new File(filePath);
            if (!file.exists()) {
                response.setStatus(404);
                throw new RuntimeException("文件不存在..");
            }
            if ("download".equals(type) || type.indexOf("download")>-1 ) {
                response.setContentType("application/force-download");// 设置强制下载不打开
                response.addHeader("Content-Disposition", "attachment;fileName=" + new String(file.getName().getBytes("UTF-8"), "iso-8859-1"));
            }
            inputStream = new BufferedInputStream(new FileInputStream(filePath));
            outputStream = response.getOutputStream();
            byte[] buf = new byte[1024];
            int len;
            while ((len = inputStream.read(buf)) > 0) {
                outputStream.write(buf, 0, len);
            }
            response.flushBuffer();
        } catch (IOException e) {
            log.error("预览文件失败" + e.getMessage());
            response.setStatus(404);
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }

    }

//	/**
//	 * 下载文件
//	 * 请求地址：http://localhost:8080/common/download/{user/20190119/e1fe9925bc315c60addea1b98eb1cb1349547719_1547866868179.jpg}
//	 *
//	 * @param request
//	 * @param response
//	 * @throws Exception
//	 */
//	@GetMapping(value = "/download/**")
//	public void download(HttpServletRequest request, HttpServletResponse response) throws Exception {
//		// ISO-8859-1 ==> UTF-8 进行编码转换
//		String filePath = extractPathFromPattern(request);
//		// 其余处理略
//		InputStream inputStream = null;
//		OutputStream outputStream = null;
//		try {
//			filePath = filePath.replace("..", "");
//			if (filePath.endsWith(",")) {
//				filePath = filePath.substring(0, filePath.length() - 1);
//			}
//			String localPath = uploadpath;
//			String downloadFilePath = localPath + File.separator + filePath;
//			File file = new File(downloadFilePath);
//	         if (file.exists()) {
//	         	response.setContentType("application/force-download");// 设置强制下载不打开            
//	 			response.addHeader("Content-Disposition", "attachment;fileName=" + new String(file.getName().getBytes("UTF-8"),"iso-8859-1"));
//	 			inputStream = new BufferedInputStream(new FileInputStream(file));
//	 			outputStream = response.getOutputStream();
//	 			byte[] buf = new byte[1024];
//	 			int len;
//	 			while ((len = inputStream.read(buf)) > 0) {
//	 				outputStream.write(buf, 0, len);
//	 			}
//	 			response.flushBuffer();
//	         }
//
//		} catch (Exception e) {
//			log.info("文件下载失败" + e.getMessage());
//			// e.printStackTrace();
//		} finally {
//			if (inputStream != null) {
//				try {
//					inputStream.close();
//				} catch (IOException e) {
//					e.printStackTrace();
//				}
//			}
//			if (outputStream != null) {
//				try {
//					outputStream.close();
//				} catch (IOException e) {
//					e.printStackTrace();
//				}
//			}
//		}
//
//	}

    /**
     * @param modelAndView
     * @return
     * @功能：pdf预览Iframe
     */
    @RequestMapping("/pdf/pdfPreviewIframe")
    public ModelAndView pdfPreviewIframe(ModelAndView modelAndView) {
        modelAndView.setViewName("pdfPreviewIframe");
        return modelAndView;
    }

    /**
     * 把指定URL后的字符串全部截断当成参数
     * 这么做是为了防止URL中包含中文或者特殊字符（/等）时，匹配不了的问题
     *
     * @param request
     * @return
     */
    private static String extractPathFromPattern(final HttpServletRequest request) {
        String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
        String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
        return new AntPathMatcher().extractPathWithinPattern(bestMatchPattern, path);
    }

    /**
     * 中转HTTP请求，解决跨域问题
     *
     * @param url 必填：请求地址
     * @return
     */
    @RequestMapping("/transitRESTful")
    public Result transitRESTful(@RequestParam("url") String url, HttpServletRequest request) {
        try {
            ServletServerHttpRequest httpRequest = new ServletServerHttpRequest(request);
            // 中转请求method、body
            HttpMethod method = httpRequest.getMethod();
            JSONObject params;
            try {
                params = JSON.parseObject(JSON.toJSONString(httpRequest.getBody()));
            } catch (Exception e) {
                params = new JSONObject();
            }
            // 中转请求问号参数
            JSONObject variables = JSON.parseObject(JSON.toJSONString(request.getParameterMap()));
            variables.remove("url");
            // 在 headers 里传递Token
            String token = TokenUtils.getTokenByRequest(request);
            HttpHeaders headers = new HttpHeaders();
            headers.set("X-Access-Token", token);
            // 发送请求
            String httpURL = URLDecoder.decode(url, "UTF-8");
            ResponseEntity<String> response = RestUtil.request(httpURL, method, headers, variables, params, String.class);
            // 封装返回结果
            Result<Object> result = new Result<>();
            int statusCode = response.getStatusCodeValue();
            result.setCode(statusCode);
            result.setSuccess(statusCode == 200);
            String responseBody = response.getBody();
            try {
                // 尝试将返回结果转为JSON
                Object json = JSON.parse(responseBody);
                result.setResult(json);
            } catch (Exception e) {
                // 转成JSON失败，直接返回原始数据
                result.setResult(responseBody);
            }
            return result;
        } catch (Exception e) {
            log.debug("中转HTTP请求失败", e);
            return Result.error(e.getMessage());
        }
    }

    /**
     * 文件上传至阿里云 - 原分片上传迁移
     * @param request
     * @param multipartFile
     * @param chunk
     * @return
     */
    @ApiOperation(value="文件上传至阿里云- 原分片上传迁移", notes="注意category参数")
//    @PostMapping("/chunkUpload") 不使用阿里云，直接用本地存储
    public Result<?> chunkUploadAliyun(HttpServletRequest request, @RequestParam("file") MultipartFile multipartFile, CscFileChunkVo chunk) {
        if (multipartFile.isEmpty()) {
            return Result.error("文件不能为空！");
        }
        return uploadAliyun(multipartFile,chunk.getCategory());
    }


    @PutMapping("/clearObsInfo")
    public Result<String> clearObsInfo() {
        return Result.OK("成功");
    }
    @ApiOperation(value="获取文件上传七牛云的凭证", notes="")
    @GetMapping("/getKodoToken")
    public Result<?> getKodoToken(@RequestParam(value = "category",defaultValue = "other")@ApiParam("文件上传的类型，根据不同类型上传不同文件夹，默认 other，pc视频上传-video；APP上传视频-appVideo；其他上传图片、文档不需要传或传 other") String category,
                                           @RequestParam(value = "fileName",required = false)@ApiParam("指定文件上传的名称，如果有同名的会被覆盖，不用传") String fileName) {
        UploadCategoryEnum categoryEnum = UploadCategoryEnum.getByCode(category);
        if (null==categoryEnum){
            return Result.error("上传的类型错误！");
        }
        QiniuUploadTokenVo tokenVo = QiniuUtil.getInstance().createUploadToken(categoryEnum,null);
        if(categoryEnum == UploadCategoryEnum.APP_VIDEO || categoryEnum == UploadCategoryEnum.VIDEO){
            JboostFile cscFile = new JboostFile();
            cscFile.setHandleStatus("processing");
            //视频就默认值，transferFile的时候可能会更新
            cscFile.setFileExt("video/mp4");
            cscFile.setAliasName(tokenVo.getFileKey());
            cscFile.setFileKey(tokenVo.getFileKey());
            if( CollUtil.isNotEmpty(tokenVo.getBitrateList()) ){
                cscFile.setBitrateList(tokenVo.getBitrateList().stream().collect(Collectors.joining(CommonConstant.SPLIT_SYMBOL)));
            }
            fileService.save(cscFile);
        }

        JSONObject json = new JSONObject();
        json.put("securityToken",tokenVo.getToken());
        json.put("bucketName",QiniuUtil.getBucket());
        json.put("fileDir",tokenVo.getFileDir());
        json.put("fileKey",tokenVo.getFileKey());
        return Result.OK(json);
    }
    @ApiOperation(value="获取文件上传OBS的信息", notes="")
    @GetMapping("/getObsInfo")
    public Result<ObsInfo> getObsInfo() {
        ObsInfo info = new ObsInfo();
        return Result.OK(info);
    }
    @ApiOperation(value="获取文件上传OSS的 stsToken", notes="")
    @GetMapping("/getStsToken")
    public Result<?> getStsToken(@RequestParam(value = "category",defaultValue = "other") String category,HttpServletRequest httpServletRequest) {
        final String requestURI = httpServletRequest.getRequestURL().toString();
        Object jsonStrObj = redisUtil.get(CacheConstant.OSS_STS_TOKEN+stsAccessKey+ossBucketName);
//        if(null!=jsonStrObj){
//            JSONObject json = JSON.parseObject(jsonStrObj.toString());
//            json.put("fileDir",OssBootUtil.getFileDir(category));
//            return Result.OK(json);
//        }
        // STS接入地址，例如sts.cn-hangzhou.aliyuncs.com。
        String endpoint = stsEndpoint;
        // 填写步骤1生成的访问密钥AccessKey ID和AccessKey Secret。

        String AccessKeyId = stsAccessKey;
        String accessKeySecret = stsSecretKey;
        // 填写步骤3获取的角色ARN。
        String roleArn = stsRoleArn;
        // 自定义角色会话名称，用来区分不同的令牌，例如可填写为SessionTest。
        String roleSessionName = "SessionTest";
        // 以下Policy用于限制仅允许使用临时访问凭证向目标存储空间examplebucket上传文件。
        // 临时访问凭证最后获得的权限是步骤4设置的角色权限和该Policy设置权限的交集，即仅允许将文件上传至目标存储空间examplebucket下的exampledir目录。
        String policy = "{\n" +
                "    \"Version\": \"1\", \n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:PutObject\"\n" +
                "            ], \n" +
                "            \"Resource\": [\n" +
                "                \"acs:oss:*:*:"+ossBucketName+"/*\" \n" +
                "            ], \n" +
                "            \"Effect\": \"Allow\"\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        try {
            // regionId表示RAM的地域ID。以华东1（杭州）地域为例，regionID填写为cn-hangzhou。也可以保留默认值，默认值为空字符串（""）。
            String regionId = "cn-hangzhou";
            // 添加endpoint。
            DefaultProfile.addEndpoint(regionId, "Sts", endpoint);
            // 构造default profile。
            IClientProfile profile = DefaultProfile.getProfile(regionId, AccessKeyId, accessKeySecret);
            // 构造client。
            DefaultAcsClient client = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setSysMethod(MethodType.POST);
            request.setRoleArn(roleArn);
            request.setRoleSessionName(roleSessionName);
            request.setPolicy(policy); // 如果policy为空，则用户将获得该角色下所有权限。
            request.setDurationSeconds(3600L); // 设置临时访问凭证的有效时间为3600秒。
            final AssumeRoleResponse response = client.getAcsResponse(request);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            System.out.println("Expiration: " + sdf2.format( sdf.parse(response.getCredentials().getExpiration())) );
            System.out.println("Access Key Id: " + response.getCredentials().getAccessKeyId());
            System.out.println("Access Key Secret: " + response.getCredentials().getAccessKeySecret());
            System.out.println("Security Token: " + response.getCredentials().getSecurityToken());
            System.out.println("RequestId: " + response.getRequestId());
            AssumeRoleResponse.Credentials credentials = response.getCredentials();
            //放入缓存
            String jsonStr = JSON.toJSONString( credentials );
            JSONObject json = JSON.parseObject(jsonStr);
            json.put("bucketName",ossBucketName);
            json.put("region","oss-cn-hangzhou");
            json.put("secure",true);
            json.put("endpoint",endpoint);
            json.put("sysServer",requestURI);
            redisUtil.set(CacheConstant.OSS_STS_TOKEN+stsAccessKey+ossBucketName,json,3000L);
            json.put("fileDir",OssBootUtil.getFileDir(category));
            return Result.OK(json);
        } catch (ClientException e) {
            System.out.println("Failed：");
            System.out.println("Error code: " + e.getErrCode());
            System.out.println("Error message: " + e.getErrMsg());
            System.out.println("RequestId: " + e.getRequestId());
            return Result.OK( e.getErrMsg(),null );
        } catch (ParseException e) {
            e.printStackTrace();
            return Result.OK( e.getMessage(),null );
        }

    }


    @ApiOperation(value="前端上传文件到 oss/其他第三方平台 后，转换成 jboost_file 使用", notes="")
    @PostMapping("/transferFile")
    public Result<?> transferFile(@Valid @RequestBody CscFileVo fileVo) {

        Result<Object> result = new Result<>();
        if(null == fileVo.getAliasName() && null !=fileVo.getFileStorePath()){
            String []paths = fileVo.getFileStorePath().split("/");
            fileVo.setAliasName(paths[paths.length-1]);
            fileVo.setFileKey(fileVo.getAliasName());
        }

        if ( null==fileVo.getFileKey() && null !=fileVo.getAliasName() ){
            fileVo.setFileKey(fileVo.getAliasName());
        }

        //jboost_file 记录
        JboostFile cscFile = fileService.getByFileKey(fileVo.getFileKey());
        boolean existsFile = true;
        if(null == cscFile){
            existsFile = false;
            cscFile = new JboostFile();
        }
        if(null!=fileVo.getFileSize()){
            cscFile.setFileSize( fileVo.getFileSize() / 1024 );
        }
        if(null!=fileVo.getAliasName()){
            cscFile.setAliasName(fileVo.getAliasName());
        }
        cscFile.setFileStore("{\"type\":\"" +  fileVo.getFileStoreType() + "\",\"path\":\"" + fileVo.getFileStorePath() + "\"}");
        if(null==fileVo.getFileExt()){
            String [] fileStr = fileVo.getFileStorePath().split("\\.");
            if(fileStr.length>1){
                fileVo.setFileExt(fileStr[fileStr.length-1]);
            }
        }
        if (null == cscFile.getFileExt()){
            cscFile.setFileExt(fileVo.getFileExt());
        }
        cscFile.setDuration(fileVo.getDuration());
        // 生成文件编码
        StringBuffer sb = new StringBuffer();
//            固定开头
        sb.append(JboostFileConstant.ATTACH_CODE_START);
//            加文件格式
        sb.append( fileVo.getFileExt().toUpperCase() ).append("-");
        int count = fileService.count();
//            加6位编码
        sb.append(SnUtils.getSn(count, 6));
        cscFile.setFileCode(sb.toString());
        //状态设置为空，不更新状态
        cscFile.setHandleStatus(null);
        fileService.saveOrUpdate(cscFile);
//        if(existsFile){
//        }else {
//            //暂时只更新文件存储和大小
//            fileService.update(new LambdaUpdateWrapper<JboostFile>().eq(JboostFile::getId,cscFile.getId()).set(JboostFile::getFileStore,cscFile.getFileStore()).set(JboostFile::getFileSize,cscFile.getFileSize()));
//        }
        result.setMessage("上传成功！");
        //这里去掉文件的码率信息
        cscFile.setBitrateList(null);
        //这里设置成功，上传完成的时候才能预览
        cscFile.setHandleStatus("success");
        //先简单实现
        JSONObject jsonResult = (JSONObject) JSON.toJSON(cscFile);
        if( CommonConstant.UPLOAD_TYPE_OSS.equals( fileVo.getFileStoreType() ) ){
            jsonResult.put("fileUrl", OssBootUtil.getFullUrl( fileVo.getFileStorePath(), ossBucketName) );
        }else if(CommonConstant.UPLOAD_TYPE_OBS.equals( fileVo.getFileStoreType() )){
            jsonResult.put("fileUrl", cscFile.getFileStore() );
        }else if(CommonConstant.UPLOAD_TYPE_KODO.equals( fileVo.getFileStoreType() )){
//            if (StringUtils.isNotEmpty(fileVo.getFileExt()) && fileVo.getFileExt().indexOf("video") >-1){
//                //视频需要使用 m3u8地址-默认使用640k
//                fileVo.setFileStorePath(fileVo.getFileStorePath()+"-1000k.m3u8");
//            }
            jsonResult.put("fileUrl", QiniuUtil.getFullUrl( fileVo.getFileStorePath(), QiniuUtil.getBucket() ) );
            if (StringUtils.isNotEmpty(fileVo.getFileExt()) && fileVo.getFileExt().indexOf("video") >-1){
                jsonResult.put("screenshotUrl", QiniuUtil.getFullUrl( fileVo.getFileStorePath()+QiniuUtil.SCREENSHOT_SUFFIX, QiniuUtil.getBucket() ) );
                jsonResult.put("playExt","video/mp4"); //上传完成后先用 mp4 播放
            }
        }else {
            jsonResult.put("fileUrl", fileVo.getFileStorePath());
        }
        result.setResult(jsonResult);
        result.setSuccess(true);
        return result;
    }


    @ApiOperation(value="获取管理员的微信列表", notes="")
    @GetMapping("/getManageWechat")
    public Result<?> getManageWechat() {
        Result<List<DictModel>> result = new Result<List<DictModel>>();
        List<DictModel> ls = null;
        //字典表
        ls = sysDictService.queryDictItemsByCode("admin_wechat");
        result.setSuccess(true);
        result.setResult(ls);
        return result;
    }

    @ApiOperation(value="获取隐私策略", notes="")
    @GetMapping("/getPrivacyPolicy")
    public Result<String> getPrivacyPolicy() {
        Result<String> result = new Result<String>();
        try {
//            String s2 = FileUtils.readTxt(ResourceUtils.getFile(privacyPolicyPath));
            String s2 =  iSysDictService.queryDictTextByKey("GETPRIVACYPOLICY", "GETPRIVACYPOLICY_URL");;
            result.setResult(s2);
        } catch (Exception e) {
            e.printStackTrace();
            result.setSuccess(false);
            result.setResult(e.getMessage());
        }
        return result;
    }

    @ApiOperation(value="获取用户服务协议", notes="")
    @GetMapping("/getServiceAgreement")
    public Result<String> getServiceAgreement() {
        Result<String> result = new Result<String>();
        try {
//            String s2 = FileUtils.readTxt(ResourceUtils.getFile(serviceAgreementPath));
            String s2 = iSysDictService.queryDictTextByKey("GETSERVICEAGREEMENT", "GETSERVICEAGREEMENT_URL");;;
            result.setResult(s2);
        } catch (Exception e) {
            e.printStackTrace();
            result.setSuccess(false);
            result.setResult(e.getMessage());
        }
        return result;
    }

    @ApiOperation(value="获取用户帮助", notes="")
    @GetMapping("/getUserHelper")
    public Result<String> getUserHelper() {
        Result<String> result = new Result<String>();
        try {
//            String s2 = FileUtils.readTxt(ResourceUtils.getFile(serviceAgreementPath));
            String s2 = iSysDictService.queryDictTextByKey("GETUSERHELPER", "GETUSERHELPER_URL");;;
            result.setResult(s2);
        } catch (Exception e) {
            e.printStackTrace();
            result.setSuccess(false);
            result.setResult(e.getMessage());
        }
        return result;
    }


}
